<template>
    <div class="main-container" @mousedown="cutstartDrawing"
                        @mousemove="cutdrawRectangle"
                        @mouseup="cutstopDrawing" ref="maincontainer">
        <div v-if="uploadLoading" class="fullscreen-loading">
            <div class="loading-content">
                <div class="spinner"></div>
                <p>文件解析中，请稍候...</p>
            </div>
        </div>

        <div class="button-container">
            <el-button @click="goBack" class="back-button" icon="ArrowLeftBold"></el-button>
        </div>
        <div class="main-card">
            <div class="card-container">
                <div class="left-card">
                    <div class="chat-list">
                        <el-scrollbar ref="scrollbarRef" >
                            <div v-for="(message, index) in messages" :key="index" class="message-container" 
                            :class="{'remote-message': !message.isLocal, 'local-message': message.isLocal}">
                                <div class="avatar">
                                    <img v-if="message.isLocal" src="/assets/local.png" alt="Avatar" />
                                    <img v-else src="/assets/remote.png" alt="Avatar" />
                                </div>
                                <div 
                                    v-if="message.text" 
                                    class="bubble" 
                                    v-html="renderMath(preprocessContent(message.text))"></div>
                                    <div class="bubble" v-if="message.image">
                                        <img  :src="message.image" alt="Message Image" class="chat-img"
                                        @click="openImageDialog(message.image)"/>
                                    </div>
                            </div>
                        </el-scrollbar>
                    </div>
                    <div class="input-area">
                        <div class="input-tools">
                            <el-button icon="Document" circle @click="triggerFileUpload"></el-button>
                            <el-button icon="VideoPause" circle @click="stopAnswer"></el-button>
                            <el-button icon="Microphone" circle @click="toggleMicrophone" :style="microphoneStyle"></el-button>
                            <el-button icon="VideoCamera" circle @click="toggleCamera" :style="videoStyle"></el-button>
                            <el-button icon="Phone" circle @click="hangupTalk" :style="hangupStyle"></el-button>
                        </div>
                        <el-input
                            class="input-message"
                            v-model="inputMessage"
                            type="textarea"
                            :autosize="{ minRows: 4, maxRows: 6 }"
                            placeholder="请输入消息"
                            @keydown="handleKeydown"
                        >
                            <template #append>
                                <el-button @click="sendMessage">发送</el-button>
                            </template>
                        </el-input>
                    </div>
                    <div class="local-player" id="local-player" ref="localPlayer" @mousedown="startDrag($event,localPlayer)">
                        <div class="video-layer"  style="display: none;">
                        
                        </div>
                    </div>
                </div>
                <div class="right-card">
                    <div class="text-display" id="text-display"  ref="textDisplay">
                        <div v-if="ispdfloading" class="loading-overlay">
                            <div class="loading-box">
                            <div class="spinner"></div>
                            <div class="loading-text">Loading...</div>
                            </div>
                        </div>

                        <div class="chart_layer" ref="chartLayer">
                            <div style="position: absolute;padding:5px"  @mousedown="startDrag($event,chartLayer)">
                                <img src="/assets/move.png"/>
                            </div>
                            <div style="position: absolute;padding:5px;top:0px;right:0px" @click="closeChartLayer">
                                <img src="/assets/close.png"/>
                            </div>
                        </div>
                    </div>

                    <div class="pagger" v-if="pdfloadsuccess">
                        <el-button @click="goPrePage" icon="ArrowLeftBold"></el-button>
                        <el-button @click="goNextPage" icon="ArrowRightBold"></el-button>
                    </div>
                    <div class="button-bar">
                        <el-button class="opt-button" circle @click="drawTypeFunc(11,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 11" src="/assets/draw11on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw11.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(1,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 0" src="/assets/draw1on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw1.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(2,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 1" src="/assets/draw2on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw2.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(3,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 2" src="/assets/draw3on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw3.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(9,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 9" src="/assets/draw9on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw9.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle  @click="drawTypeFunc(4,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 3" src="/assets/draw4on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw4.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle  @click="drawTypeFunc(10,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 10" src="/assets/draw10on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw10.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(5,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 4" src="/assets/draw5on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw5.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(7,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 7" src="/assets/draw6on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw6.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <el-button class="opt-button" circle @click="drawTypeFunc(8,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 8" src="/assets/draw7on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw7.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button>
                        <!-- <el-button class="opt-button" circle @click="drawTypeFunc(12,$event)">
                            <template #icon>
                                <img v-if="currentDrawType === 12" src="/assets/draw12on.png" alt="Custom Icon" class="custom-icon" />
                                <img v-else src="/assets/draw12.png" alt="Default Icon" class="custom-icon" />
                            </template>
                        </el-button> -->
                        <el-button class="opt-button" circle @click="drawTypeFunc(6)">
                            <template #icon>
                                <img src="/assets/draw8.png" alt="Custom Icon" class="custom-icon" />
                            </template>
                        </el-button>
                    </div>

                    <div v-if="isZoomLayerVisible" class="zoom-layer"  @wheel="handleWheel">
                        <el-button @click="zoomIn">放大</el-button>
                        <el-button @click="zoomOut">缩小</el-button>
                    </div>
                    <div v-if="isColorSelectVisible" class="zoom-layer">
                        <div class="color-picker-cover" @click="closePicker"></div>
                            <div class="color-picker-content">
                                <div class="color-palette">
                                <div 
                                    v-for="color in colorPalette" 
                                    :key="color"
                                    class="color-swatch"
                                    :style="{ backgroundColor: color }"
                                    @click="selectColor(color)"
                                ></div>
                                </div>
                                <div class="color-preview" :style="{ backgroundColor: selectedColor }" @click="selectColor(selectedColor)">
                                {{ selectedColor }}
                                </div>
                                <input 
                                type="color" 
                                v-model="selectedColor" 
                                class="native-color-input"
                                >
                            </div>
                    </div>
                </div>
            </div>
        </div>
        <input type="file" ref="fileInput" @change="handleFileChange" style="display: none;">

        <div v-if="isCutDrawing"
                 class="selection-rectangle"
                 :style="{
                                left: rectangle.left + 'px',
                                top: rectangle.top + 'px',
                                width: rectangle.width + 'px',
                                height: rectangle.height + 'px',
                                }"></div>

        <el-dialog v-model="dialogVisible" width="60%" top="25vh">
            <div style="text-align: center;">
                <img :src="currentImage" style="max-width: 100%; max-height: 70vh;" />
            </div>
            <template #footer>
                <span class="dialog-footer">
                <!-- <el-button @click="dialogVisible = false">关闭</el-button> -->
                <el-button type="primary" @click="downloadImage(currentImage)">
                    下载图片
                </el-button>
                </span>
            </template>
            </el-dialog>
    </div>
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'
import { ref, computed, nextTick,onMounted,onUnmounted, shallowRef, defineAsyncComponent } from 'vue'
import http from '@/api/request';
import katex from 'katex'
import 'katex/dist/katex.min.css'
import Board from '@volcengine/white-board-manage';
import {ToolMode,InputFormat,
    OutputFormat,StorageType,ViewMode,
    TaskStatus,BkFillType,TranscodeMode,
    WhiteBoardRoomEventsTypes } from '@volcengine/white-board-manage'
import { ElMessage } from 'element-plus'

import AvatarPlatform, {
  PlayerEvents,
  SDKEvents,
} from '@/avatar/index.js'
import * as THREE from 'three'
import { FontLoader,TextGeometry } from 'three/examples/jsm/Addons.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import axios from 'axios';


const router = useRouter();
const scrollbarRef = ref(null);
const localPlayer = ref(null);
const chartLayer = ref();
const fileInput = ref(null);
const error = ref(null);
const textDisplay = ref(null);
const maincontainer = ref(null);

const currentDrawType = ref(0);

//视频框拖拽
let isDragging = false
let dragOffset = { x: 0, y: 0 }

let sessionId = null; //当前交互session id

const isZoomLayerVisible = ref(false); //显示缩放层
const isColorSelectVisible = ref(false); //显示颜色选择浮层
const selectedColor = ref('#3aa757');
// 预设颜色板
const colorPalette = ref([
  '#3aa757', '#e8453c', '#f9bb2d', '#4688f1',
  '#ffffff', '#000000', '#ff9ff3', '#feca57',
  '#ff6b6b', '#48dbfb', '#1dd1a1', '#576574'
]);
//白板颜色设置
const selectColor = (color) => {
  selectedColor.value = color;
  isColorSelectVisible.value = false;
  currentWhiteBoard.setShapeColor(selectedColor.value);
  currentWhiteBoard.setPenColor(selectedColor.value);
  currentWhiteBoard.setTextColor(selectedColor.value);
};


//白板截图工具
const isCutDrawing = ref(false);
const isScreenshotMode = ref(false);
const rectangle = ref({
    left: 0,
    top: 0,
    width: 0,
    height: 0
  });
const startPos = ref({ x: 0, y: 0 });
const cutstartDrawing = (e) => {
    if (!isScreenshotMode.value) return;
    isCutDrawing.value = true;

    const scale = getPageScale();
    const scaledX = e.clientX / scale;
    const scaledY = e.clientY / scale;
    
    startPos.value = {
      x: scaledX,
      y: scaledY
    };
    
    rectangle.value = {
      left: scaledX,
      top: scaledY,
      width: 0,
      height: 0
    };
  };
const cutdrawRectangle = (e) => {
    if (!isScreenshotMode.value) return;
    if (!isCutDrawing.value) return;

    const scale = getPageScale();
    const currentX = e.clientX / scale;
    const currentY = e.clientY / scale;
    
    rectangle.value = {
      left: Math.min(currentX, startPos.value.x),
      top: Math.min(currentY, startPos.value.y),
      width: Math.abs(currentX - startPos.value.x),
      height: Math.abs(currentY - startPos.value.y)
    };
  };
  


const cutstopDrawing = async () => {
    if (!isScreenshotMode.value) return;
    if (!isCutDrawing.value) return;
    isCutDrawing.value = false;
    
    // 确保矩形有足够的尺寸
    if (rectangle.value.width > 10 && rectangle.value.height > 10) {
        isScreenshotMode.value = false;
    //   await captureAndDownload();

        try {
            const imageBlob = await captureToBlob();
            //上传截图到tos
            const formData = new FormData();
            formData.append('file', imageBlob, `screenshot-${Date.now()}.png`);
            http.post('/3rdpartai/upload2Tos',formData,{
                headers: {
                    'Content-Type': 'multipart/form-data',
                    'token':token
                }
            }).then(response => {
                console.log("上传成功",response.data);
                let url = response.data.data.fileUrl;
                messages.value.push({image:url, isLocal: true});
                scrollToBottom();
                //调用模型解析截取内容
                axios.post('http://localhost:5000/analysisPic',{
                            url:url
                        }).then(response => {
                            if (chartScene!=null) {
                                disposeScene(chartScene);
                            }

                            let result = JSON.parse(response.data.result);
                            // console.log("result",result);
                            let codes = result.choices[0].message.content;
                            console.log("codes",codes);
                            codes = codes.replace("```javascript","");
                            codes = codes.replace("```","");

                            window.THREE = THREE;
                            const script = document.createElement('script');
                            script.textContent = codes;
                            document.body.appendChild(script);
                            drawCoordinateAxes(chartScene);
                            document.body.removeChild(script);
                            chartLayer.value.style.display = 'block';
                        }).catch(error=>{
                            chartLayer.value.style.display = 'block';
                            const geometry = new THREE.BufferGeometry();
                            const vertices = new Float32Array([
                                0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
                                1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1,
                                0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1,
                                0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1,
                                0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
                                1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1,
                                0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,
                                0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1,
                                0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0,
                                0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
                                0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1
                            ]);
                            geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
                            const material = new THREE.LineBasicMaterial({ color: 0x000000 });
                            const line = new THREE.LineSegments(geometry, material);
                            chartScene.add(line);
                        });
                needNewMsg = true;
                //发送图片给大模型
                // http.post("/3rdpartai/api/chat/image",
                //         {
                //             sessionId:sessionId,
                //             imageUrl:url,
                //             text:"请识别图中的内容，结合之前的题目讲讲图中内容的含义，概念或者细节"
                //         },
                //         {
                //             headers: {
                //                 'Content-Type': 'application/json',
                //                 'token':token
                //             }
                //         }).then(async (response) => {
                //             console.log("发送图片消息",response);
                //         });

            });
        } catch (error) {
            console.error('上传失败:', error);
        }
    }
    
    // 重置矩形
    rectangle.value = { left: 0, top: 0, width: 0, height: 0 };
  };

  //截图转blob
  const captureToBlob = async () => {
    const html2canvas = await import('html2canvas');
    const scale = getPageScale();
    
    const options = {
        scrollX: -maincontainer.value.scrollLeft*scale,
        scrollY: -maincontainer.value.scrollTop*scale,
        x: (rectangle.value.left + maincontainer.value.scrollLeft)*scale,
        y: (rectangle.value.top + maincontainer.value.scrollTop)*scale,
        width: rectangle.value.width*scale,
        height: rectangle.value.height*scale,
        // scale,
        useCORS: true,
        allowTaint: true
    };
    
    const canvas = await html2canvas.default(maincontainer.value, options);
    
    return new Promise((resolve) => {
        canvas.toBlob((blob) => {
        resolve(blob);
        }, 'image/png');
    });
};


//消息图片大图展示逻辑
const dialogVisible = ref(false);
// 当前显示的图片URL
const currentImage = ref('');
const openImageDialog = (imageUrl) => {
  currentImage.value = imageUrl;
  dialogVisible.value = true;
};


  //下载图片
  const downloadImage = (dataUrl, filename) => {
    const link = document.createElement('a');
    link.href = dataUrl;
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };



//视频窗口拖拽
const startDrag = (event: MouseEvent,target: HTMLElement) => {
    isDragging = true
    dragOffset.x = event.clientX - target.offsetLeft
    dragOffset.y = event.clientY - target.offsetTop

    const onDrag = (event: MouseEvent) => {
        if (isDragging) {
            target.style.left = `${event.clientX - dragOffset.x}px`
            target.style.top = `${event.clientY - dragOffset.y}px`
        }
    }

    const stopDrag = () => {
        isDragging = false
        document.removeEventListener('mousemove', onDrag)
        document.removeEventListener('mouseup', stopDrag)
    }

    document.addEventListener('mousemove', onDrag)
    document.addEventListener('mouseup', stopDrag)
}

const getPageScale = () => {
  const bodyStyle = window.getComputedStyle(document.body);
  const transform = bodyStyle.getPropertyValue('transform');
  if (transform && transform !== 'none') {
    const matrix = transform.match(/^matrix\((.+)\)$/);
    if (matrix) {
      const values = matrix[1].split(', ').map(Number);
      return values[0]; 
    }
  }
  return 1;
};

const getTextDisplayDimensions = () => {
    if (textDisplay.value) {
    const rect = textDisplay.value.getBoundingClientRect();
    
    // 获取body的实际缩放比例
    const bodyStyle = window.getComputedStyle(document.body);
    const transform = bodyStyle.getPropertyValue('transform');
    let scale = getPageScale();
    
    const scaledWidth = rect.width / scale;
    const scaledHeight = rect.height / scale;
    
    console.log('Scaled Width:', scaledWidth);
    console.log('Scaled Height:', scaledHeight);
    return { width: scaledWidth, height: scaledHeight };
  }
  return { width: 0, height: 0 };
};

function preprocessContent(text) {
  // 预处理内容，修复常见的LaTeX语法问题
//   console.log("text",text);
  return text
      .replace(/\\vec\{([^}]+)\}/g, '\\overrightarrow{$1}') // 转换\vec为KaTeX支持的overrightarrow
      .replace(/\\left\\\{/g, '{')
      .replace(/\\right\\\}/g, '}')
      .replace(/\\text\{([^}]+)\}/g, '\\mathrm{$1}');
}

//数学公式渲染
function renderMath(text) {
  if (!text) return ''

  // 处理换行
  const withLineBreaks = text.replace(/\n/g, '<br>')

  // 渲染数学公式
  return withLineBreaks.replace(/\\\(([^]+?)\\\)/g, (match, math) => {
    try {
      return katex.renderToString(math, {
        throwOnError: false,
        displayMode: false,
        macros: {
          '\\vec': '\\mathbf{#1}',      // 新增
          '\\overrightarrow': '\\vec',  // 兼容overrightarrow
          '\\text': '\\mathrm{#1}', // 自定义\text宏
          '\\trac': '\\frac{#1}{#2}' // 自定义\trac宏
        }
      })
    } catch (e) {
      console.error('KaTeX渲染错误:', e)
      ElMessage.error('KaTeX渲染错误！')
      return `<span class="katex-error">${match}</span>`
    }
  })
}

//文件上传触发
const triggerFileUpload = () => {
    fileInput.value.click() 
}

//打断智能体回答
const stopAnswer =async ()=>{
    await http.post(
            "/vertc/proxyAIGCFetch?Action=UpdateVoiceChat",
            {
                "command":"interrupt",
                "interruptMode":1
            },
            {
                headers: {
                'Content-Type': 'application/json',
                'token':token
                }
            });
}

//图片处理，获取图片url
async function processImageFile(imageUrl,width,height) {
    const img = await loadImage(imageUrl);
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, 0, 0);

    return canvasToBlobUrl(canvas);
}


//文件选择上传处理 
const handleFileChange = async (event: Event) => {
    const files = (event.target as HTMLInputElement).files
    if (files && files.length > 0) {
        const file = files[0]
        console.log('Selected file:', file)
        const allowedTypes = ['image/png', 'image/jpeg','application/pdf'];
        if (!allowedTypes.includes(file.type)) {
            ElMessage.error('只能上传图片或pdf格式的文件');
            uploadLoading.value = false;
            return;
        }
        uploadLoading.value = true;

        const formData = new FormData();
        formData.append('file', file);
        error.value = null

        try {
            //上图到tos
            http.post('/3rdpartai/upload2Tos',formData,{
            headers: {
                'Content-Type': 'multipart/form-data',
                'token':token
            }
            }).then(response => {
                console.log(response.data);
                const {width,height} = getTextDisplayDimensions();
                if (response.data.data.fileType!='pdf') {
                    
                    try{
                        http.post("/3rdpartai/api/chat/image",
                        {
                            sessionId:"",
                            imageUrl:response.data.data.fileUrl,
                            text:"识别图中的题目并输出，不要解答"
                        },
                        {
                            headers: {
                                'Content-Type': 'application/json',
                                'token':token
                            }
                        }).then(async (response) => {
                            uploadLoading.value = false;
                            currentPage = 0;
                            console.log("解析结果",response.data.choices[0].message.content);
                            ElMessage.success("题目已解析");
                            sessionId = response.data.sessionId;
                            let imageUrl = URL.createObjectURL(file);
                            imageUrl = await processImageFile(imageUrl,width,height);
                            currentLoction = 280;
                                pdfimages = [imageUrl];
                                // setTimeout(async ()=>{
                                //         const url = await drawOnImageAndGetBlobUrl(pdfimages[currentPage], {
                                //         answer: [{text:"√",x:480,y:100,}]
                                //     });
                                //     console.log("pdfimages",pdfimages);
                                //     pdfimages = [url];
                                //     currentWhiteBoard.setPageBackground({ bkImage: url, bkImageFillType: BkFillType.kCenter });
                                // },2000);


                                let dpageId = currentWhiteBoard.getCurrentPageId();
                                const ids = [];
                                if (currentWhiteBoard.getPageCount()>1) {
                                    for (let i=0;i<currentWhiteBoard.getPageCount();i++){
                                        if (currentWhiteBoard.getPageInfoByIndex(i).pageId!=dpageId) {
                                            ids.push(currentWhiteBoard.getPageInfoByIndex(i).pageId);
                                        }
                                    }
                                }
                            
                                if (ids.length>1) {
                                    currentWhiteBoard.removePages(ids)
                                        .then(function(res) {
                                            currentWhiteBoard.createPages([
                                            {
                                                pageId: 'page_' + Date.now(),
                                            },
                                        ],{
                                            autoFlip: true,
                                        }).then(function() {
                                            setTimeout(() => {
                                                currentWhiteBoard.removePages([dpageId]).then(()=>{
                                                    // currentWhiteBoard.addImage(imageUrl);
                                                    currentWhiteBoard.setPageBackground({bkImage:imageUrl,bkImageFillType:BkFillType.kCenter});
                                                });
                                            }, 1000);
                                        }).catch(function(err) {
                                            console.error('createPages', '调用失败', err);
                                        });
                                    }).catch(function(err) {
                                        console.error('removePages', '调用失败', err);
                                    });
                                } else {
                                    currentWhiteBoard.createPages([{
                                            pageId: 'page_' + Date.now(),
                                        },
                                        ],{
                                            autoFlip: true,
                                        }).then(function() {
                                        setTimeout(() => {
                                            currentWhiteBoard.removePages([dpageId]).then(()=>{
                                                currentWhiteBoard.setPageBackground({bkImage:imageUrl,bkImageFillType:BkFillType.kCenter});
                                                // currentWhiteBoard.addImage(imageUrl,{top:10,left:10});
                                            });
                                        }, 1000);
                                    }).catch(function(err) {
                                        console.error('createPages', '调用失败', err);
                                    });
                                }
                            
                        }).catch(e=>{
                            uploadLoading.value = false;
                            console.error(e);
                        });
                    }catch(e){
                        console.log(e);
                        uploadLoading.value = false;
                        ElMessage.error("题目解析失败");
                    }

                } else {
                    currentPage = 0;
                    loadPdfFile(response.data.data.fileUrl,width,height);
                }
            }).catch(e=>{
                ElMessage.error("上传图片失败");
                uploadLoading.value = false;
            });
        } catch (err) {
            console.error('获取题目失败:', err);
            ElMessage.error("文件上传异常!");
            error.value = '加载题目失败，请稍后重试'
            uploadLoading.value = false;
        }
    }
}


//rtc基本配置，及参数获取
const userId = localStorage.getItem('username');
const token = localStorage.getItem('token');
const config = {
    appId: localStorage.getItem('appId'),
    roomId: localStorage.getItem('roomId'),
    tokens: [
    {
      userId: userId,
      token: token
    }]
}
const streamOptions = {
  audio: true,
  video: true,
};

let rtc = null;
let whiteBoardRoom = null;
let currentWhiteBoard = null;

const messages = ref([]);
const inputMessage = ref<string>('')

const microphoneOpen = ref(true)
const videoOpen = ref(true)
const isLeave = ref(false)

const bucket = "whiteboard";

const defaultBoardInfo = {
  boardId: 1,
  pages: [{
    pageId: "wb_default",
    bkInfo: {},
    extra: ""
  }],
  bkInfo: {
    bkColor: "",
    bkImage: ""
  }
};

//pdf加载完成标记
const pdfloadsuccess = ref(false);
//pdf解析标记
const ispdfloading = ref(false);
//文件上传中标记
const uploadLoading = ref(false);
let pdfimages = null; //pdf图片列表
let currentPage = 0; //当前白板页码
// let currentBgImage = null; //当前白板背景图片

//返回
const goBack = async () => {
    await actionLeave();
    await leaveWhiteboardRoom();
    router.go(-1)
}


const responses = ref([]);
let eventSource = null;
//发送消息
const sendMessage = async () => {
    if (inputMessage.value.trim()) {
        const msg = inputMessage.value;
        await http.post(
            "/vertc/proxyAIGCFetch?Action=UpdateVoiceChat",
            {
                "command":"ExternalPromptsForLLM",    // ExternalTextToLLM
                "message":msg,
                "interruptMode":1
            },
            {
                headers: {
                'Content-Type': 'application/json',
                'token':token
                }
            });
        messages.value.push({ text: msg, isLocal: true })
        inputMessage.value = ''
        needNewMsg = true;
        scrollToBottom();
    }
}

const openEventSource = () => {
      if (eventSource) {
        eventSource.close();
      }

      eventSource = new EventSource('http:localhost:5000/talktorobot', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ msg: message.value })
      });

      eventSource.onmessage = (event) => {
        const data = JSON.parse(event.data);
        responses.value.push(data.msg);
      };

      eventSource.onerror = (err) => {
        console.error('EventSource failed:', err);
        eventSource.close();
      };
    };

const goPrePage = () => {
    if (currentWhiteBoard && currentPage>0) {
        currentWhiteBoard.flipPrevPage();
        currentPage--;
        console.log("image",pdfimages[currentPage]);
        sendImageTorobot(pdfimages[currentPage]);
    } else {
        console.log("object null");
    }
};

const goNextPage = () => {
    if (currentWhiteBoard && currentPage < pdfimages.length) {
        currentWhiteBoard.flipNextPage();
        currentPage++;
        console.log("image",pdfimages[currentPage]);
        sendImageTorobot(pdfimages[currentPage]);
    } else {
        console.log("object null");
    }
};

//发送图片给ai
const sendImageTorobot = (img) =>{
    try {
        const formData = new FormData();
        formData.append('imageUrl', img);
        http.post('/vertc/uploadFileAndAnalyse',formData,{
        headers: {
        'Content-Type': 'multipart/form-data',
        'token':token
        }
        }).then(response => {
            console.log(response.data.data.analyseContent);
            ElMessage.success("题目已解析");
            });
        } catch (err) {
            console.error('获取题目失败:', err);
             ElMessage.success("题目解析失败");
        }
}

const scrollToBottom = async () => {
  await nextTick();
  if (scrollbarRef.value) {
    const wrap = scrollbarRef.value.$el.querySelector('.el-scrollbar__wrap');
    wrap.scrollTop = wrap.scrollHeight;
  }
};

const handleKeydown = (event: KeyboardEvent) => {
    if (event.key === 'Enter' && !event.shiftKey) {
        event.preventDefault() // 阻止默认的换行行为
        sendMessage()
    }
}

//白板工具栏action
const drawTypeFunc = (type,event) => {
    try {
        switch (type) {
            case 1:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.PENCIL_BRUSH);
                currentDrawType.value = 0;
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;
            case 2:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.TEXT);
                currentDrawType.value = 1;
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;
            case 3:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.CIRCLE);
                currentDrawType.value = 2;
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;
            case 4:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.LINE);
                currentDrawType.value = 3;   
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;   
            case 5:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.ERASER);
                currentDrawType.value = 4;   
                currentWhiteBoard.resetZoom(); 
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;    
            case 6:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.clearPage();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;        
            case 7:
                currentWhiteBoard.setViewMode(ViewMode.kBroadcast);
                currentDrawType.value = 7;  
                isZoomLayerVisible.value = !isZoomLayerVisible.value;
                currentWhiteBoard.setEditType(ToolMode.ZOOM);
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;
            case 8:
                // event.stopPropagation();
                isScreenshotMode.value = !isScreenshotMode.value;
                // 退出截图模式时重置状态
                if (!isScreenshotMode.value) {
                    isCutDrawing.value = false;
                    rectangle.value = { left: 0, top: 0, width: 0, height: 0 };
                }
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.ZOOM);
                currentDrawType.value = 8;
                isZoomLayerVisible.value = false;
                isColorSelectVisible.value = false;
                break;
            case 9:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.RECT);
                currentDrawType.value = 9;
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;
            case 10:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                currentWhiteBoard.setEditType(ToolMode.ARROW);
                currentDrawType.value = 10;
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                isColorSelectVisible.value = false;
                break;
            case 11:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                isColorSelectVisible.value = true;
                currentDrawType.value = 11;
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
                break;
            case 12:
                currentWhiteBoard.setViewMode(ViewMode.kFollow);
                isColorSelectVisible.value = false;
                currentDrawType.value = 12;
                if (isRecording) {
                    stopRecording();
                } else {
                    startRecording();
                }
                
                currentWhiteBoard.resetZoom();
                isZoomLayerVisible.value = false;
                isScreenshotMode.value = false;
            break;
        }
    } catch (e) {
        console.error('设置绘制工具失败:', e);
        ElMessage.error('设置绘制工具失败!');
    }
}


const zoomIn = () => {
    if (currentWhiteBoard) {
        currentWhiteBoard.zoomIn(0.2);
    }
};
const zoomOut = () => {
    if (currentWhiteBoard) {
        currentWhiteBoard.zoomOut(0.2);
    }
};

//鼠标缩放白板
const handleWheel = (event: WheelEvent) => {
    if (event.deltaY < 0) {
        zoomIn();
    } else {
        zoomOut();
    }
};


//图片加载封装
function loadImage(url) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.crossOrigin = 'Anonymous';
        img.src = url;
    });
}
//blob转url
function canvasToBlobUrl(canvas) {
    return new Promise(resolve => {
        canvas.toBlob(blob => {
            const file = new File([blob], 'modified-image.png', { type: 'image/png' });
            resolve(URL.createObjectURL(file));
        }, 'image/png');
    });
}


//sleep封装
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

//将模型消息添加到白板
let currentLoction = 280;
let lastStep = "";
async function addInfoToWhiteBoard(info) {
    if (pdfimages==null || pdfimages.length ==0) {
        return;
    }
    let scape = 25;
    let type = info.type;
    if (type == lastStep && type=="concept"){
        return;
    }
    let txt = "";
    if (type == "concept") {
        txt = "涉及的核心概念:";
    } else if (type== "step") {
        txt = "解题步骤梳理:";
    } else if (type == "answer") {
        txt = "最终答案是:";
    }

    if (lastStep != type) {
        const url = await drawOnImageAndGetBlobUrl(pdfimages[currentPage], {
                lines: [],
                texts: [{ text:txt, x: 20, y: currentLoction, color: "blue" }]
        });

        pdfimages[currentPage] = url;
        currentWhiteBoard.setPageBackground({ bkImage: url, bkImageFillType: BkFillType.kCenter });
        currentLoction += scape;
        await sleep(1000);
    }
    lastStep = type;
    if (type == "concept" && info.points!=null) {
        for (let i = 0; i < info.points.length; i++) {
            const yrange = currentLoction + (i * scape);
            const text = " "+info.points[i]+"、";

            // 绘制当前文本
            const url = await drawOnImageAndGetBlobUrl(pdfimages[currentPage], {
                lines: [],
                texts: [{ text, x: 40, y: yrange, color: "red" }]
            });

            // 更新白板背景
            pdfimages[currentPage] = url;
            currentWhiteBoard.setPageBackground({ bkImage: url, bkImageFillType: BkFillType.kCenter });

            if (i == info.points.length-1) {
                currentLoction = yrange + scape;
            } else {
                await sleep(1000);
            }
        }
    }
    if (type=='step') {
        let text = info.desc+":"+info.formula;
        const url = await drawOnImageAndGetBlobUrl(pdfimages[currentPage], {
                lines: [],
                texts: [{ text, x: 40, y: currentLoction, color: "red" }]
            });
        pdfimages[currentPage] = url;
        currentWhiteBoard.setPageBackground({ bkImage: url, bkImageFillType: BkFillType.kCenter });
        currentLoction += scape;

        // if (info.formula!=null && info.formula!="") {
        //     await sleep(1000);
        //     let text = info.formula;
        //     const url = await drawOnImageAndGetBlobUrl(pdfimages[currentPage], {
        //             lines: [],
        //             texts: [{ text, x: 40, y: currentLoction, color: "red" }]
        //         });
        //     pdfimages[currentPage] = url;
        //     currentWhiteBoard.setPageBackground({ bkImage: url, bkImageFillType: BkFillType.kCenter });
        //     currentLoction += scape;
        // }
    }
    if (type=='answer') {
        let text = info.value;
        const url = await drawOnImageAndGetBlobUrl(pdfimages[currentPage], {
                texts: [{ text, x: 40, y: currentLoction, color: "red" }],
                answer:[{text:"√", x: info.coordinates[0], y: info.coordinates[1]}]
            });
        pdfimages[currentPage] = url;
        currentWhiteBoard.setPageBackground({ bkImage: url, bkImageFillType: BkFillType.kCenter });
        currentLoction += scape;
    }
    
}

//白板绘制 直线和文本到图片
async function drawOnImageAndGetBlobUrl(imageUrl, options = { lines: [], texts: [],answer:[] }) {
    if (pdfimages.length>0) {
        if (imageUrl.startsWith('http')) {
            const response = await fetch(imageUrl);
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            const blob = await response.blob();
            imageUrl = URL.createObjectURL(blob);
        }

        const img = await loadImage(imageUrl);
        const canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);

        // 绘制直线
        if (options.lines!=null) {
            options.lines.forEach(line => {
                ctx.beginPath();
                ctx.moveTo(line.startX, line.startY);
                ctx.lineTo(line.endX, line.endY);
                ctx.strokeStyle = line.color || 'blue';
                ctx.lineWidth = line.width || 2;
                ctx.stroke();
            });
        }


        // 绘制文字
        if (options.texts!=null) {
            options.texts.forEach(text => {
                ctx.fillStyle = text.color || 'red';
                ctx.font = text.font || '16px Arial';
                ctx.textAlign = text.align || 'left';
                ctx.textBaseline = text.baseline || 'top';
                ctx.fillText(text.text, text.x, text.y);
            });
        }
        
        if (options.answer!=null) {
            options.answer.forEach(text =>{
                ctx.fillStyle = text.color || 'red';
                ctx.font = text.font || '48px Arial';
                ctx.textAlign = text.align || 'left';
                ctx.textBaseline = text.baseline || 'top';
                // ctx.fillText(text.text, text.x, text.y);
                ctx.fillText(text.text, 480, 100);
            })
        }

        return canvasToBlobUrl(canvas);
    }

    return imageUrl
}


//白板消息长连接处理
let whiteboardEventSource:EventSource;
function whiteboardConnect(){
    whiteboardEventSource = new EventSource('/apiedu/3RDPARTAI/api/tts/stream');

    whiteboardEventSource.onmessage = function(event){
        console.log("接收到白板消息");
        console.log("whiteboardEventSource",event.data);
        let result = JSON.parse(event.data);
        if (result.type=="whiteboard") {
                // console.log("whiteboard",result.data[0].whiteboard);
                setTimeout(()=>{
                    addInfoToWhiteBoard(result.data[0].whiteboard);
            },2000);
        } else if(result.type=="audio_text") {
            //播放语音
            if (result.data!=null) {
                for (let i = 0; i < result.data.length; i++) {
                    let url = "https://192.168.15.200/ftp/"+result.data[i].filePath.replace("/mnt/hhit-new/ftp/","");
                    console.log("url",url);
                    addAudioToQueue(url);
                    if (messages.value.length > 0 && messages.value[messages.value.length - 1].text=='思考中...') {
                        messages.value.pop();
                    }
                    messages.value.push({ text:  result.data[0].text, isLocal: false});
                }
            }
        }
    };

    whiteboardEventSource.onerror = function(error) {
        console.log("whiteboardEventSource",error);
    }
}

//断开白饭长连接
function whiteboardDisconnect(){
    whiteboardEventSource.close();
}



//图标绘制
let chartScene;
function initChartScene() {
    chartScene = new THREE.Scene();
    chartScene.background = new THREE.Color(0xf0f0f0);

    let camera = new THREE.PerspectiveCamera(
        75,chartLayer.value.clientWidth / chartLayer.value.clientHeight,
        0.1, 1000);
    camera.position.z = 5;

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    const controls = new OrbitControls(camera, renderer.domElement);
    renderer.setSize(chartLayer.value.clientWidth, chartLayer.value.clientHeight);
    chartLayer.value.appendChild(renderer.domElement);

    const axesHelper = new THREE.AxesHelper(5); 
    chartScene.add(axesHelper);

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(chartScene, camera);
    }
    animate();

    addAxisLabels();
    addOriginMarker();
}

function disposeScene(scene) {
    while(scene.children.length > 0) { 
        const object = scene.children[0];
        
        if (object.isMesh) {
            if (object.geometry) {
                object.geometry.dispose(); // 释放几何体
            }
            
            if (object.material) {
                if (Array.isArray(object.material)) {
                    object.material.forEach(material => material.dispose());
                } else {
                    object.material.dispose();
                }
            }
        }
        scene.remove(object);
    }

    const axesHelper = new THREE.AxesHelper(5); 
    scene.add(axesHelper);
    addAxisLabels();
    addOriginMarker();
}

function closeChartLayer(){
    chartLayer.value.style.display = 'none';
}

//添加轴标记
function addAxisLabels() {
    const loader = new FontLoader();
    
    // 使用 Three.js 示例中的字体
    loader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', (font) => {
        const textParams = {
            font: font,
            size: 0.2,
            height: 0.05,
            depth:0.05,
            curveSegments: 12
        };
        
        // X轴标签
        const textGeoX = new TextGeometry('X', textParams);
        const textMatX = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        const textX = new THREE.Mesh(textGeoX, textMatX);
        textX.position.set(5.5, 0, 0);
        chartScene.add(textX);
        
        // Y轴标签
        const textGeoY = new TextGeometry('Y', textParams);
        const textMatY = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
        const textY = new THREE.Mesh(textGeoY, textMatY);
        textY.position.set(0, 5.5, 0);
        chartScene.add(textY);
        
        // Z轴标签
        const textGeoZ = new TextGeometry('Z', textParams);
        const textMatZ = new THREE.MeshBasicMaterial({ color: 0x0000ff });
        const textZ = new THREE.Mesh(textGeoZ, textMatZ);
        textZ.position.set(0, 0, 5.5);
        chartScene.add(textZ);
    });
}

//添加原点标记
function addOriginMarker() {
    // 原点小球
    const originGeometry = new THREE.SphereGeometry(0.01, 16, 16);
    const originMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const originMarker = new THREE.Mesh(originGeometry, originMaterial);
    chartScene.add(originMarker);
    
    // 原点文字标签
    const loader = new FontLoader();
    loader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', (font) => {
        const originTextGeo = new TextGeometry('O', {
            font: font,
            size: 0.2,
            depth:0.05,
            curveSegments: 8
        });
        const originTextMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        const originText = new THREE.Mesh(originTextGeo, originTextMat);
        originText.position.set(-0.5, -0.5, 0);
        chartScene.add(originText);
    });
}





onMounted(async() => {
    rtc = new RtcClient({
        config,
        streamOptions,
        handleUserPublishStream,
        handleUserUnpublishStream,
        handleUserStartVideoCapture,
        handleUserStopVideoCapture,
        handleUserJoin,
        handleUserLeave,
        handleEventError,
        handleRemoteStreamStats,
        handleLocalStreamStats,
        handleAudioDeviceStateChanged,
        handleLocalAudioPropertiesReport,
        handleRemoteAudioPropertiesReport,
        handleUserMessageReceived,
        handleUserStartAudioCapture,
        handleUserStopAudioCapture,
        handleRoomBinaryMessageReceived,
        handleNetworkQuality
    });

    try{
        rtc.bindEngineEvents();
        console.log('token',token);
        console.log('roomid',config.roomId);
        console.log('userid',userId);
        await rtc.join(token, config.roomId, userId);
        console.log('join room success!');
        try{
            rtc.createLocalStream();
        }catch(e){console.log(e)}
        //添加智能体到频道
        await addRobot();
        await addWhiteboard();
    }catch(e){
        ElMessage.error("添加智能体失败");
        console.log(e);
    }

    whiteboardConnect();

    initChartScene();

});

onUnmounted(async() => {
    if (rtc!=null){
        rtc.removeEventListener();
        rtc.leave();
        removeRobot();
        await leaveWhiteboardRoom();
    }

    whiteboardDisconnect();
});


let currentRecordCanvas = null;
//添加白板
const addWhiteboard = async () => {
    //创建白板
    console.log('appid',config.appId);
    const {width,height} = getTextDisplayDimensions();
    Board.init({
        domId: 'text-display',
        appId:config.appId,
        boardSize:{
            height:height,
            width:width
        }
        // appId:"6368706a480497018ab6db30"
    });
    const boardRoomId = "whiteboard_"+config.roomId;
    const boardUserId = "whiteboard_"+userId;

    //为board用户单独获取token
    const response = await http.get("/vertc/getToken?roomId="+boardRoomId+"&userId="+boardUserId, 
            {
                headers: {
                    'Content-Type': 'application/json'
                }
            });
        console.log(response);
        if (response.status === 200) {
            //参数配置
            console.log("board roomId",boardRoomId);
            console.log("board userId",boardUserId);
            console.log("board token",response.data);

            Board.joinRoom({
                roomId:boardRoomId,
                userId:boardUserId,
                token:response.data
                // roomId:"4285e475-b67f-4777-ab36-1fbb584119fd",
                // userId:"9df175fd-4bb9-4197-9217-3b2dd2459d15",
                // token:"0016368706a480497018ab6db30eAB190kKVTzqZ2VK6mckADQyODVlNDc1LWI2N2YtNDc3Ny1hYjM2LTFmYmI1ODQxMTlmZCQAOWRmMTc1ZmQtNGJiOS00MTk3LTkyMTctM2IyZGQyNDU5ZDE1BQAAANWN62cBANWN62cCANWN62cDANWN62cEAAAAAAAgAHVY114dSql6fkpqZrne2zsoI8h4JJQfKL3aoo4BAlr5",
                // defaultBoardInfo:{}
            }).then(function (boardRoom) {
                whiteBoardRoom = boardRoom;
                console.log("白板join room 成功", boardRoom);
                whiteBoardRoom.on(WhiteBoardRoomEventsTypes.onRemoveWhiteBoard, function(event) {
                    console.log('删除白板成功');
                });

                whiteBoardRoom.on("onCurrentWhiteBoardChanged", ({ whiteBoard }) => {
                    // console.log('白板创建成功,房间号' + whiteBoardRoom.getRoomId());
                    currentWhiteBoard = whiteBoard;
                    currentWhiteBoard.setShapeColor(selectedColor.value);
                    currentWhiteBoard.setPenColor(selectedColor.value);
                    currentWhiteBoard.setTextColor(selectedColor.value);
                    try {
                        // currentWhiteBoard.setEditType(ToolMode.PENCIL_BRUSH);
                        currentDrawType.value = 0;
                        console.log('绘制工具已设置为 PENCIL_BRUSH');
                    } catch (e) {
                        console.error('设置绘制工具失败:', e);
                    }
                    currentWhiteBoard.on('onBoardBackgroundChanged', (e) => {
                        console.log("background changed",e);
                    });
                    currentWhiteBoard.on('onZoomInfoChanged',(e)=>{
                        console.log("zoom changed",e);
                    });
                    currentWhiteBoard.on('onRecordUpdated',(e)=>{
                        //操作记录回调
                        console.log("record changed",e);
                    });
                    // currentWhiteBoard.setViewMode

                    currentRecordCanvas = document.getElementsByClassName("upper-canvas")[0];
                });
            }).catch(err=> {
                console.error('房间加入失败',err);
                ElMessage.error('加入白板房间失败');
            });
        } else {
            alert('获取token失败')
            ElMessage.error('获取白板token失败');
        }
};

//关闭白板
const leaveWhiteboardRoom = async () => {
    if (whiteBoardRoom) {
       await whiteBoardRoom.leaveRoom();  
    }
}

let videoRecorder; 
let isRecording = false;
function startRecording() {
    if (currentRecordCanvas!=null) {
        isRecording = true;
        const stream = currentRecordCanvas.captureStream(25);
        videoRecorder = new MediaRecorder(stream, {
                    mimeType: 'video/webm;codecs=vp9'
                    });
        const chunks = [];
        videoRecorder.ondataavailable = (e) => {
            chunks.push(e.data);
        };
        videoRecorder.onstop = () => {
            // 合并所有数据块
            const blob = new Blob(chunks, { type: 'video/webm' });
            const url = URL.createObjectURL(blob);
            
            // 创建下载链接
            const a = document.createElement('a');
            a.href = url;
            a.download = 'canvas-recording.webm';
            a.click();
        };
        videoRecorder.start();
    }
}
function stopRecording(){
    if (videoRecorder!=null) {
        isRecording = false;
        videoRecorder.stop();
    }
}

//pdf加载
const loadPdfFile = async (url,width,height)=> {
        pdfloadsuccess.value = false;
        ispdfloading.value = true;
        pdfimages = null;
        try {
            console.log("发起转码中...");
            const transcodeRes = await whiteBoardRoom.createTranscodeTask({
                app_id: config.appId,
                resource: url,
                operator: "whiteboard_"+userId,
                pre_sign_duration: 3600 * 24,
                transcode_mode: TranscodeMode.static,
                transcode_config: {
                    input_format: InputFormat.pdf,
                    output_format: OutputFormat.png,
                    output_width: Math.floor(width),
                    output_height: Math.floor(height),
                    thumbnail: false
                },
                storage_config: {
                    type: StorageType.Tos,
                    tos_config: {
                        account_id: "2100068960",
                        bucket:bucket
                    }
                },
                onProgress: (transcodePercent, transcodeStatus, task_id) => {
                    if (transcodeStatus === TaskStatus.Fail) {
                        console.log("转码失败!");
                        ElMessage.error('文件转码失败');
                        ispdfloading.value = false;
                    } else {
                        console.log(`转码中，任务 id 是 ${task_id}，进度 ${transcodePercent}%`);
                    }
                }
                });

                console.log("转码成功!开始创建白板");
                const {
                    images
                } = transcodeRes;
                const pic = images.sort((a, b) => a.page_id - b.page_id).map(i => i.img);
                await createWhiteBoardWidthFile(pic);
                uploadLoading.value = false;
        } catch (error) {
            console.log(error);
            ElMessage.error('转码异常');
            ispdfloading.value = false;
            uploadLoading.value = false;
        }
}

async function createWhiteBoardWidthFile(pics) {
    pdfimages = pics;
    pdfloadsuccess.value = pdfimages.length > 1;
    console.log("pics",pdfimages);
  const pageConfig = pics.map((url, index) => {
    return {
      pageId: "" + index,
      bkInfo: {
        bkColor: "",
        bkImage: url,
        bkImageFillType: BkFillType.kCenter
      }
    };
  });

  corePdfLoad(pageConfig);
  //默认解析第一页文本
  sendImageTorobot(pdfimages[0]);
}

const corePdfLoad = (pageConfig)=>{
    try {
        whiteBoardRoom.createWhiteBoard({
        boardId: parseInt((Math.random() * 1000).toFixed(0)),
        pages: pageConfig,
        bkInfo: defaultBoardInfo.bkInfo || undefined
        }).then(_ref => {
        let {
            whiteBoard
        } = _ref;
        console.log("白板创建成功!");
        currentWhiteBoard = whiteBoard;
        try {
                // currentWhiteBoard.setEditType(ToolMode.PENCIL_BRUSH);
                currentDrawType.value = 0;
                console.log('绘制工具已设置为 PENCIL_BRUSH');
            } catch (e) {
                console.error('设置绘制工具失败:', e);
            } finally {
                ispdfloading.value = false;
            }
            }).catch(err => {
                console.log("白板创建失败!");
                ElMessage.error('创建白板失败');
                pdfloadsuccess.value = false;
                ispdfloading.value = false;
            });
        } catch (err) {
            console.error("静态转码创建白板失败", err);
            ElMessage.error('静态转码创建白板失败');
            pdfloadsuccess.value = false;
            ispdfloading.value = false;
    }
}


const actionLeave = async () => {
  rtc.isMicOn = false;
  rtc.changeMicOrVideoIconUrl('mic', rtc.isMicOn, rtc.OFFMICICON, rtc.ONMICICON);
  rtc.isVideoOn = false;
  rtc.changeMicOrVideoIconUrl('video', rtc.isVideoOn, rtc.OFFVIDEOICON, rtc.ONVIDEOICON);
  rtc.removeEventListener();
  removeRobot();
//   leaveWhiteboardRoom();
  await rtc.leave();
};

let toggleMicrophone = async () => {
    rtc.isMicOn = !rtc.isMicOn;
    microphoneOpen.value = rtc.isMicOn;
    await rtc.changeAudioState(rtc.isMicOn);
    rtc.changeMicOrVideoIconUrl('mic', rtc.isMicOn, rtc.OFFMICICON, rtc.ONMICICON);
    if (microphoneOpen.value) {
        ElMessage.success("麦克风已打开");
    } else {
        ElMessage.success("麦克风已关闭");
    }
};

let toggleCamera = async () => {
    try{
        rtc.isVideoOn = !rtc.isVideoOn;
        videoOpen.value = rtc.isVideoOn;
        console.log('toggleCamera', rtc.isVideoOn);

        if (rtc.isVideoOn) {
            localPlayer.value.style.display = 'block';
            ElMessage.success("相机已打开");
        } else {
            localPlayer.value.style.display = 'none';
            ElMessage.success("相机已关闭");
        }
        await rtc.changeVideoState(rtc.isVideoOn);
        rtc.changeMicOrVideoIconUrl('video', rtc.isVideoOn, rtc.OFFVIDEOICON, rtc.ONVIDEOICON);
    }catch(e){
        console.log(e);
    }
};

let hangupTalk = async () => {
    if (!isLeave.value) {
        isLeave.value = true;
        videoOpen.value = false;
        microphoneOpen.value = false;
        localPlayer.value.style.display = 'none';
        await actionLeave();
    } else {
        isLeave.value = false;
        try{
            rtc.bindEngineEvents();
            console.log('token',token);
            console.log('roomid',config.roomId);
            console.log('userid',userId);
            await rtc.join(token, config.roomId, userId);
            console.log('join room success!');
            try{
                rtc.createLocalStream();
            }catch(e){console.log(e)}
            addRobot();
            isLeave.value = false;
            videoOpen.value = true;
            microphoneOpen.value = true;
            localPlayer.value.style.display = 'block';
            ElMessage.success("通话已挂断");
        }catch(e){
            console.log(e);
            ElMessage.error("挂断异常");
        }
    }
};

const microphoneStyle =  computed(() => {
  return {
    backgroundColor: microphoneOpen.value ? 'green' : '#f0f2f5',
    color: microphoneOpen.value ? 'white' : 'currentcolor' 
  };
});

const videoStyle =  computed(() => {
  return {
    backgroundColor: videoOpen.value ? 'green' : '#f0f2f5',
    color: videoOpen.value ? 'white' : 'currentcolor' 
  };
});
const hangupStyle =  computed(() => {
    return {
    backgroundColor: !isLeave.value ? 'red' : '#f0f2f5',
    color: !isLeave.value ? 'white' : 'currentcolor' 
  };
});


let avatarPlatform=null;
async function addAdavart(){
  avatarPlatform = new AvatarPlatform() 
  // 可以选择性 按需 进行相关事件监听
  avatarPlatform
      .on(SDKEvents.connected, (initResp: any) => {
        console.log('sdk event: connected', initResp)
      })
      .on(SDKEvents.stream_start, () => {
        console.log('sdk event: stream_start')
      })
      .on(SDKEvents.disconnected, (err: any) => {
        console.log('sdk event: disconnected')
        if (err) {
          console.error('ws link disconnected because of Error')
          console.error(e.code, e.message, e.name, e.stack)
        }
      })
      .on(SDKEvents.asr, (asrData: any) => {
        console.log('sdk event: asr', asrData)
      })
      .on(SDKEvents.nlp, (nlpData: any) => {
        console.log('sdk event: nlp', nlpData)
      })
      .on(SDKEvents.frame_start, (frameData: any) => {
        console.log('sdk event: frameBegin', frameData)
      })
      .on(SDKEvents.tts_duration, (sessionData: any) => {
        console.log('sdk event: duration', sessionData)
      })
      .on(SDKEvents.frame_stop, (frameData: any) => {
        console.log('sdk event: frameEnd', frameData)
      })
      .on(SDKEvents.error, (error: any) => {
        console.log('sdk event: error', error)
      })
      .on(SDKEvents.action_start, (actionData: any) => {
        console.log('sdk event: actionBegin', actionData)
      })
      .on(SDKEvents.action_stop, (actionData: any) => {
        console.log('sdk event: actionEnd', actionData)
      });

    const player = avatarPlatform.player || avatarPlatform.createPlayer()
    player
    // ?.on(PlayerEvents.error, (err: any) => {
    //     console.log('sdk player event: player error', err)
    //     if (err?.code === '700005') {
    //       console.log('sdk player event: player h264 not supported')
    //     }
    //   })
      ?.on(PlayerEvents.play, () => {
        console.log('sdk event: player play')
      })
      .on(PlayerEvents.waiting, () => {
        console.log('sdk event: player waiting')
      })
      .on(PlayerEvents.playing, () => {
        console.log('sdk event: player playing')
      })
      .on(PlayerEvents.playNotAllowed, () => {
        console.log('sdk event: play not allowed, muted play')
      })


  // PlayerEvents 常量枚举
  enum PlayerEvents {
    play = 'play',
    waiting = 'waiting',
    playing = 'playing',
    playNotAllowed = 'not-allowed',
  }

  avatarPlatform
  .setApiInfo({
    appId: 'a7854e67',//到交互平台-接口服务中获取，appid需要发布后使用
    apiKey: 'fabdf4e4de2306652eb05b866b8cf4e9',//到交互平台-接口服务中获取
    apiSecret: 'NDkxOTE2MjMyZTdmODc0OGFmNDgyMzMw',//到交互平台-接口服务中获取
    sceneId: '163092082846732288',// //到交互平台-接口服务中获取，传入“接口服务ID”
    serverUrl: 'wss://avatar.cn-huadong-1.xf-yun.com/v1/interact'
  })
  // 设置全局/连接 参数
  .setGlobalParams({
    avatar_dispatch: { interactive_mode: 0, content_analysis: 0 },
    stream: {
      protocol: 'xrtc',//（必穿）实时视频协议，支持webrtc/xrtc，其中只有xrtc支持透明背景，需参数alpha传1
      alpha: 0,
      bitrate: 1000000,
      fps: 25,
    },
    avatar: {
      avatar_id: '110017006', //授权的形象资源id，到交互平台-接口服务-形象列表中获取已授权的形象
      width: 720,
      height: 1280,
      mask_region: '[0, 0, 1080, 1920]',
      scale: 1,
      move_h: 0,
      move_v: 0,
      audio_format: 1,
    }, 
    tts: {
      vcn: 'x4_xiaozhong', //授权的声音资源id，到交互平台-接口服务-声音列表中获取已授权的声音
      speed: 50,
      pitch: 50,
      volume: 100,
    },
    subtitle: {
      subtitle: 0,
      font_color: '#ffffff',
    },
      background: {
      enabled: false,
      type: 'url',
      data: '',
    },
  })

  //发起连接
  await avatarPlatform
      .start({
        wrapper: document.querySelector('.video-layer') as HTMLDivElement
      })
      .then(() => {
        console.log('connected &&  stream play successfully')
      })
      .catch((e: any) => {
        console.error(e.code, e.message, e.name, e.stack)
      })
}

async function removeAdavart(){
  avatarPlatform.stop();
  avatarPlatform.destroy()
}


async function addRobot(){
    const response = await http.post(
        "/vertc/proxyAIGCFetch?Action=StartVoiceChat",{},
        {
          headers: {
              'Content-Type': 'application/json',
              'token':token
          }
        });
    console.log("添加robot:"+response);
    // addAdavart();
}

async function removeRobot() {
    const response = await http.post(
        "/vertc/proxyAIGCFetch?Action=StopVoiceChat",{},
        {
          headers: {
              'Content-Type': 'application/json',
              'token':token
          }
        });
    // removeAdavart();
    console.log("移除robot:"+response);
}


function handleUserJoin(e) {
  console.log('handleUserJoin', e);
}

function handleUserLeave(e) {
  console.log('handleUserLeave', e);
}


async function handleUserPublishStream(stream) {
  console.log('handleUserPublishStream', stream);
  const { userId, mediaType } = stream;
  const remoteUserId = userId;
  if (mediaType & rtc.MediaType.VIDEO) {
    const player = $(`#player-wrapper-${remoteUserId}`);
    if (player[0]) {
      rtc.setRemoteVideoPlayer(remoteUserId, player[0]);
    }
  }
}

function handleUserUnpublishStream(stream) {
  const { userId, mediaType } = stream;

  if (mediaType & rtc.MediaType.VIDEO) {
    rtc.setRemoteVideoPlayer(userId, undefined);
  }
}

function handleEventError(e) {
  if (e.errorCode === VERTC.ErrorCode.DUPLICATE_LOGIN) {
    // actionToLeave();
    alert('你的账号被其他人顶下线了');
    // closeModal();
    rtc.autoPlayFailUser = [];

    if (rtc!=null){
        rtc.removeEventListener();
        rtc.leave();
        removeRobot();
    }

    router.push('/login');
  }
}

async function handleUserStartVideoCapture(event) {
}

function handleUserStopVideoCapture(event) {
  const { userId } = event;

  rtc.setRemoteVideoPlayer(userId, undefined);
}

function handleRemoteStreamStats(event){
    // console.log('handleRemoteStreamStats', event);
}
function handleLocalStreamStats(event){
    // console.log('handleLocalStreamStats', event);
}
function handleAudioDeviceStateChanged(event){
    // console.log('handleAudioDeviceStateChanged', event);
}
function handleLocalAudioPropertiesReport(event){
    // console.log('handleLocalAudioPropertiesReport', event);
}
function handleRemoteAudioPropertiesReport(event){
    // console.log('handleRemoteAudioPropertiesReport', event);
}
function handleUserMessageReceived(event){
    // console.log('handleUserMessageReceived', event);
}
function handleUserStartAudioCapture(event){
    // console.log('handleUserStartAudioCapture', event);
}
function handleUserStopAudioCapture(event){
    // console.log('handleUserStopAudioCapture', event);
}
let receivedMsg = "";
let currentUser = "";
let needNewMsg = false;
function handleRoomBinaryMessageReceived(event){
    // console.log('handleRoomBinaryMessageReceived',event);
    const result = tlv2String(event.message);
    const msgResult = JSON.parse(result.value);

    if (result.type === "conv") {
        //接受消息
        if (msgResult.Stage != null) {
            if (msgResult.Stage.Description === "answering") {
                //开始回答
                receivedMsg = "";
                needNewMsg = false;
                if (messages.value.length > 0 && messages.value[messages.value.length - 1].text=='思考中...') {
                    messages.value.pop();
                }
                messages.value.push({ text: '', isLocal: false});

            }

            if (msgResult.Stage.Description === "listening") {
                //接受语音输入
                receivedMsg = "";
                needNewMsg = false;
                if (messages.value.length > 0 && messages.value[messages.value.length - 1].text=='思考中...') {
                    messages.value.pop();
                }
                messages.value.push({ text: '', isLocal: true});
            }
        }
    } else if (result.type === "subv") {
        if (msgResult.data!=null){
            let msg = "";
            msgResult.data.forEach((item) => {
                msg += item.text;
            });
            if(msg.trim()=="") {
                return;
            }

            currentUser = msgResult.data[0].userId;

            if (needNewMsg) {
                //console.log("currentUser:"+currentUser+",userId:"+userId);
                if (currentUser == "BotName001") {
                    messages.value.push({ text: receivedMsg.trim(), isLocal: false})

                } else {
                    messages.value.push({ text: receivedMsg.trim(), isLocal: true})
                }

                if (!msgResult.data[0].definite) {
                    receivedMsg = "";
                }
                needNewMsg = false;
            }

            
            // console.log("needNewMsg:" + needNewMsg);
            // console.log("msg:" + msg);
            // console.log("s",msgResult.data[0]);
            console.log("definite:" + msgResult.data[0].definite)
            // console.log("paragraph:" + msgResult.data[0].paragraph)
            console.log(currentUser,msg);
            if (msgResult.data[0].definite) { //段落结尾标志
                messages.value[messages.value.length - 1].text = msg;
                needNewMsg = true;
                if (currentUser != "BotName001") {
                    messages.value.push({
                        text: '思考中...',
                        isLocal: false
                    });

                }
            } else { //非段落结尾则直接更新到消息
                receivedMsg = msg;
                messages.value[messages.value.length - 1].text = receivedMsg.trim();
            }
            nextTick(() => {
                scrollToBottom();
            });
        }
    }
}
function handleNetworkQuality(event){
    // console.log('handleNetworkQuality', event);
}       

function tlv2String(tlvBuffer) {
    const typeBuffer = new Uint8Array(tlvBuffer, 0, 4);
    const lengthBuffer = new Uint8Array(tlvBuffer, 4, 4);
    const valueBuffer = new Uint8Array(tlvBuffer, 8);

    let type = '';
    for (let i = 0; i < typeBuffer.length; i++) {
      type += String.fromCharCode(typeBuffer[i]);
    }

    const length =
      (lengthBuffer[0] << 24) | (lengthBuffer[1] << 16) | (lengthBuffer[2] << 8) | lengthBuffer[3];

    const value = new TextDecoder().decode(valueBuffer.subarray(0, length));
    return { type, value };
  }


//音频播放
let isAudioPlay = false;
const audioQueue = [];
function addAudioToQueue(audioUrl) {
    audioQueue.push(audioUrl);
    if (!isAudioPlay) {
        playNext();
    }
}
function playNext() {
    if (audioQueue.length === 0) {
        isAudioPlay = false;
        return;
    }
    
    const nextAudio = new Audio(audioQueue.shift());
    isAudioPlay = true;
    
    nextAudio.addEventListener('ended', function() {
        playNext();
    });
    
    nextAudio.play().catch(e => {
        console.error("播放失败:", e);
        playNext();
    });
}
</script>

<style scoped src="@/views/chat.css">
</style>